﻿using XinLife.Application.Interface;
using XinLife.Model;
using XinLife.Model.Dto;
using XinLife.Core.Model;
using XinLife.Core.Extention;
using System.Data.Common;
using XinLife.Core.Helper;
using SqlSugar;

namespace XinLife.Application.Implement
{
    public class ModuleService : BaseService, IModuleService
    {
        public ModuleService(IBaseRepository baseRepository) : base(baseRepository) { }

        public async Task<AjaxResult> DelModuleAsync(string ids)
        {
            string[] cModuleIds = ids.Split(',');
            var buttons = await _db.Queryable<ModuleButton>().Where(t => cModuleIds.Contains(t.cModuleId)).ToListAsync();

            try
            {
                await _db.Ado.BeginTranAsync();

                await _db.Deleteable<Module>().Where(t => cModuleIds.Contains(t.cId)).ExecuteCommandAsync();
                await _db.Deleteable<ModuleButton>(t => cModuleIds.Contains(t.cModuleId)).ExecuteCommandAsync();
                //删除所有关于菜单的权限
                await _db.Deleteable<Authorize>(t => cModuleIds.Contains(t.cItemId) && t.cItemType == 1).ExecuteCommandAsync();
                //删除所有关于按钮的权限
                await _db.Deleteable<Authorize>(t => buttons.Select(t => t.cId).Contains(t.cItemId) && t.cItemType == 2).ExecuteCommandAsync();

                await _db.Ado.CommitTranAsync();
            }
            catch (Exception ex)
            {
                await _db.Ado.RollbackTranAsync();
                throw ex;
            }

            return Success("删除成功");
        }

        public async Task<AjaxResult> DelModuleButton(string ids)
        {
            string[] cIds = ids.Split(',');
            var r = await _db.Deleteable<ModuleButton>().In(cIds).ExecuteCommandAsync();
            await _db.Deleteable<Authorize>().Where(t => cIds.Contains(t.cItemId) && t.cItemType == 2).ExecuteCommandAsync();

            if (r > 0)
            {
                return Success("删除成功");
            }
            else
            {
                return Success("删除失败");
            }
        }

        public async Task<AjaxResult> EditModuleAsync(Module module)
        {
            module.cName = module.cTitle;

            if (string.IsNullOrWhiteSpace(module.cId))
            {
                await _db.Insertable(module).ExecuteCommandAsync();

                if (module.buttons != null && module.buttons.Any())
                {
                    List<ModuleButton> buttons = new List<ModuleButton>();
                    for (int i = 0; i < module.buttons.Count(); i++)
                    {
                        string title = "";
                        if (module.buttons[i] == "x-add")
                        {
                            title = "新增";
                        }
                        else if (module.buttons[i] == "x-edit")
                        {
                            title = "编辑";
                        }
                        else if (module.buttons[i] == "x-delete")
                        {
                            title = "删除";
                        }
                        else if (module.buttons[i] == "x-batch-delete")
                        {
                            title = "批量删除";
                        }
                        buttons.Add(new ModuleButton()
                        {
                            cId = Guid.NewGuid().ToString(),
                            cModuleName = module.cName,
                            cModuleId = module.cId,
                            cEnabled = true,
                            cCreatedBy = "system",
                            cCreatedDate = DateTime.Now,
                            cEnCode = module.buttons[i],
                            cSortCode = i + 1,
                            cTitle = title
                        });
                    }
                    await _db.Insertable(buttons).ExecuteCommandAsync();
                }
                return Success("添加成功", module);
            }
            else
            {
                await _db.Updateable(module).ExecuteCommandAsync();
                return Success("修改成功", module);
            }
        }

        public async Task<AjaxResult> EditModuleButton(ModuleButton moduleButton)
        {
            if (string.IsNullOrWhiteSpace(moduleButton.cId))
            {
                await _db.Insertable(moduleButton).ExecuteCommandAsync();
                return Success("添加成功");
            }
            else
            {
                await _db.Updateable(moduleButton).ExecuteCommandAsync();
                return Success("修改成功");
            }
        }

        public async Task<AjaxResult> GetModuleButtonById(string id)
        {
            var data = await _db.Queryable<ModuleButton>().InSingleAsync(id); ;
            return Success(data);
        }
        public async Task<AjaxResult> GetModuleRoles(string moduleId, string buttonIds)
        {
            List<string> ids = new List<string>();
            var b = buttonIds?.Split(',');
            if (b != null)
            {
                ids.AddRange(b);
            }
            ids.Add(moduleId);
            string sql = $@"select a.cId,a.cName,case when b.cobjectId is not null then 1 else 0 end as cEnabled from tb_role a
                           left join(select cobjectId from  tb_authorize  where cObjectType=1 and cItemId in @itemIds  group by cobjectId having count(1)>={ids.Count}) b on b.cobjectId=a.cId";
            var roles = await _db.Ado.SqlQueryAsync<Role>(sql, new { itemIds = ids });


            var queryableRight = _db.Queryable<Authorize>().Where(t => t.cObjectType == 1 && ids.Contains(t.cItemId)).GroupBy(t => t.cObjectId).Having(t => SqlFunc.AggregateCount(t.cObjectId) > ids.Count);
            roles = await _db.Queryable<Role>()
                               .LeftJoin(queryableRight, (a, b) => a.cId == b.cObjectId)
                               .Select((a, b) => new Role { cId = a.cId, cName = a.cName, cEnabled = SqlFunc.IIF(b.cObjectId != null, true, false) })
                               .ToListAsync();


            return Success(new { allRoles = roles?.Select(t => new { value = t.cId, title = t.cName }), authRoles = roles.Where(t => t.cEnabled == true)?.Select(t => t.cId) });
        }
        public async Task<AjaxResult> GetRoleModules(string moduleId, string roleIds)
        {
            var rolecIds = roleIds.Split(',');
            //查询是否共有菜单
            var count = await _db.Queryable<Authorize>().Where(t => t.cObjectType == 1 && rolecIds.Contains(t.cObjectId) && t.cItemId == moduleId).CountAsync();
            if (count == rolecIds.Length)
            {
                int length = rolecIds.Length;
                var buttonIds = await _db.Queryable<ModuleButton>().Where(t => t.cModuleId == moduleId).ToListAsync(t => t.cId);
                var hasButtons = _db.Queryable<Authorize>().Where(t => t.cObjectType == 1 && rolecIds.Contains(t.cObjectId) && buttonIds.Contains(t.cItemId))
                                                           .GroupBy(a => a.cItemId)
                                                           .Having(a => SqlFunc.AggregateCount(a.cItemId) >= length)
                                                           .ToList(a => a.cItemId);
                //共有的 按钮 
                return Success(new { hasModule = true, hasButtons });
            }
            return Success(new { hasModule = false });
        }


        public async Task<AjaxResult> ButtonsRoleAuth(ButtonsAuthInputDto dto)
        {
            var buttonIds = await _db.Queryable<ModuleButton>().Where(t => t.cModuleId == dto.moduleId).ToListAsync(t => t.cId);
            try
            {
                await _db.Ado.BeginTranAsync();

                await _db.Deleteable<Authorize>().Where(t => dto.roleIds.Contains(t.cObjectId) && t.cItemId == dto.moduleId && t.cItemType == 1).ExecuteCommandAsync();
                await _db.Deleteable<Authorize>().Where(t => dto.roleIds.Contains(t.cObjectId) && buttonIds.Contains(t.cItemId) && t.cItemType == 2).ExecuteCommandAsync();

                if (dto.hasModule)
                {
                    List<Authorize> authorizes = new List<Authorize>();
                    //菜单--->角色
                    var module_auths = dto.roleIds.Select(t => new Authorize()
                    {
                        cId = Guid.NewGuid().ToString("N"),
                        cObjectId = t,
                        cObjectType = 1,
                        cItemId = dto.moduleId,
                        cItemType = 1,
                        cCreatedBy = AspNetUser.UserId,
                        cCreatedDate = DateTime.Now
                    });
                    authorizes.AddRange(module_auths);
                    //按钮--->角色
                    if (dto.buttonIds != null)
                    {
                        foreach (var buttonId in dto.buttonIds)
                        {
                            var buttons_auths = dto.roleIds.Select(t => new Authorize()
                            {
                                cId = Guid.NewGuid().ToString("N"),
                                cObjectId = t,
                                cObjectType = 1,
                                cItemId = buttonId,
                                cItemType = 2,
                                cCreatedBy = AspNetUser.UserId,
                                cCreatedDate = DateTime.Now
                            });
                            authorizes.AddRange(buttons_auths);
                        }
                    }
                    await _db.Insertable(authorizes).ExecuteCommandAsync();
                }
                await _db.Ado.CommitTranAsync();
            }
            catch (Exception ex)
            {
                await _db.Ado.RollbackTranAsync();
                throw ex;
            }
            return Success("ok");
        }
        public async Task<PageData<ModuleButton>> GetModuleButtonPageList(Pagination page, string queryJson)
        {
            var queryParam = queryJson.ToJObject();
            string? moduleId = queryParam.Value<string>("moduleId");

            if (moduleId.IsEmpty())
            {
                return new PageData<ModuleButton>();
            }

            RefAsync<int> totalCount = 0;
            var roles = await _db.Queryable<ModuleButton>()
                     .WhereIF(!moduleId.IsEmpty(), a => a.cModuleId == moduleId)
                     .OrderBy((a) => a.cSortCode, OrderByType.Asc)//倒序
                     .ToPageListAsync(page.pageIndex, page.pageSize, totalCount);

            return new PageData<ModuleButton>()
            {
                count = totalCount,
                entitys = roles
            };
        }

        public async Task<AjaxResult> GetModuleById(string id)
        {
            var data = await _db.Queryable<Module>().InSingleAsync(id);
            return Success(data);
        }

        public async Task<PageData<ModuleOutputDto>> GetModulePageListAsync(Pagination page, string queryJson)
        {
            var queryParam = queryJson.ToJObject();

            string? title = queryParam.Value<string>("title");
            string? isParent = queryParam.Value<string>("isParent");
            string? parentId = queryParam.Value<string>("parentId");

            RefAsync<int> totalCount = 0;
            var modules = await _db.Queryable<Module>()
                     .WhereIF(!title.IsEmpty(), a => a.cTitle.Contains(title))
                     .WhereIF(!isParent.IsEmpty(), a => a.cIsMenu.ToString() == isParent)
                     .WhereIF(!parentId.IsEmpty(), a => a.cParentId == parentId)
                     .OrderBy((a) => a.cSortCode, OrderByType.Asc)//倒序
                     .ToPageListAsync(page.pageIndex, page.pageSize, totalCount);

            Func<List<Module>, string, List<ModuleOutputDto>> res = null;
            //递归0.0
            res = (List<Module> list, string parentid) =>
            {
                var items = list.FindAll(t => t.cParentId == parentid).OrderBy(t => t.cSortCode).ToList();

                var b = new List<ModuleOutputDto>();

                items.ForEach(t =>
                {
                    b.Add(new ModuleOutputDto()
                    {
                        Id = t.cId,
                        Title = t.cTitle,
                        Icon = t.cIcon,
                        Name = t.cTitle,
                        CompName = t.cName,
                        CompPath = t.cPath,
                        Path = t.cPath,
                        IsMenu = t.cIsMenu == 0 ? true : false,
                        ParentId = t.cParentId,
                        SortCode = t.cSortCode,
                        Description = t.cDescription,
                        Enabled = t.cEnabled,
                        Children = res(list, t.cId)
                    });
                });
                return b;
            };


            return new PageData<ModuleOutputDto>()
            {
                count = totalCount,
                entitys = res(modules, "0"),
            };
        }

        public async Task<List<Module>> GetParentIdModule()
        {
            return await _db.Queryable<Module>().Where(t => t.cIsMenu == 0).OrderBy(t => t.cSortCode).ToListAsync();
        }

        public Task<List<Module>> GetUserModule(string userId, bool isAdmin = false)
        {
            if (isAdmin)
            {
                return _db.Queryable<Module>().ToListAsync();
            }
            return _db.Queryable<Module>()
                    .InnerJoin<Authorize>((a, b) => a.cId == b.cItemId)
                    .InnerJoin<Role>((a, b, c) => b.cObjectId == c.cId)
                    .InnerJoin<UserRole>((a, b, c, d) => d.cRoleId == c.cId)
                    .InnerJoin<User>((a, b, c, d, e) => e.cId == d.cUserId)
                    .Where((a, b, c, d, e) => b.cItemType == 1 && b.cObjectType == 1 && e.cId == userId)
                    .Distinct()
                    .OrderBy(a => a.cSortCode)
                    .ToListAsync();
        }

        public Task<List<ModuleButton>> GetUserModuleButtons(string userId, bool isAdmin = false)
        {
            if (isAdmin)
            {
                return _db.Queryable<ModuleButton>().OrderBy(t => t.cSortCode).ToListAsync();
            }
            return _db.Queryable<Authorize, ModuleButton>((a, b) => a.cItemId == b.cId && a.cItemType == 2)
                             .Where((a, b) => SqlFunc.Subqueryable<UserRole>().Where(s => s.cRoleId == a.cObjectId && s.cUserId == userId).Any())
                             .OrderBy((a, b) => b.cSortCode)
                             .Select((a, b) => b)
                             .ToListAsync();
        }
        public async Task<List<ModuleOutputDto>> GetUserMenu(string userId, bool isAdmin = false)
        {
            var data = await GetUserModule(userId, isAdmin);
            Func<List<Module>, string, List<ModuleOutputDto>> res = null;
            //递归0.0
            res = (List<Module> list, string parentid) =>
            {
                var items = list.FindAll(t => t.cParentId == parentid).OrderBy(t => t.cSortCode).ToList();

                var b = new List<ModuleOutputDto>();

                items.ForEach(t =>
                {
                    b.Add(new ModuleOutputDto()
                    {
                        Id = t.cId,
                        Title = t.cTitle,
                        Icon = t.cIcon,
                        Name = t.cTitle,
                        CompName = t.cName,
                        CompPath = t.cPath,
                        Path = t.cPath,
                        Children = res(list, t.cId)
                    });
                });
                return b;
            };
            return res(data, "0");
        }

        public async Task<Dictionary<string, List<string>>> GetUserMenuButtons(string userId, bool isAdmin = false)
        {
            var buttonList = new List<ModuleButton>();
            if (isAdmin)
            {
                buttonList = await _db.Queryable<ModuleButton>().ToListAsync();
            }
            else
            {
                buttonList = await _db.Queryable<Authorize, ModuleButton>((a, b) => a.cItemId == b.cId && a.cItemType == 2)
                             .Where((a, b) => SqlFunc.Subqueryable<UserRole>().Where(s => s.cRoleId == a.cObjectId && s.cUserId == userId).Any()).Select((a, b) => b).ToListAsync();
            }

            var dicButton = new Dictionary<string, List<string>>();
            foreach (var item in buttonList)
            {
                if (item.cModuleName == null) continue;
                if (dicButton.Keys.Contains(item.cModuleId))
                {
                    dicButton[item.cModuleId].Add(item.cEnCode);
                }
                else
                {
                    dicButton.Add(item.cModuleId, new List<string>() { item.cEnCode });
                }
            }
            return dicButton;
        }
    }
}
